package registration.servlet;

import java.net.*;
import java.sql.SQLException;
import java.util.Collection;

import javax.annotation.Resource;
import javax.ws.rs.*;
import javax.ws.rs.core.*;
import javax.ws.rs.core.Response.Status;

import org.json.*;

import registration.Consensus;
import user.User;
import user.servlet.UsersResource;

import common.Pair;
import common.exceptions.*;
import common.servlet.*;

@Resource
@Path("/cons")
@SuppressWarnings({"javadoc", "static-method"})
public class ConsensusResource extends AbstractResource {

	@GET
	@Produces(MediaType.APPLICATION_JSON)
	@Path("/{conId}")
	public Response retrieve(@PathParam("conId") long conId,
			@CookieParam(value = UsersResource.COOKIE_NAME) Long sessionId) {
		try (ManagersBundle mb = new ManagersBundle()) {
			User user = null;
			if (sessionId != null) {
				user = EventResource.getUserFromSession(sessionId, mb);
			}
			Consensus con = mb.rm.getConsensus(conId);
			JSONObject object = EventResource.conToJson(con, mb, user);
			mb.commit();
			return Response.ok(object).build();
		} catch (InvalidKeyException e) {
			return Response.status(Status.NOT_FOUND).build();
		} catch (RuntimeException | SQLException e) {
			return handleException(e);
		}
	}

	@GET
	@Path("/{conId}/votes/{userId}")
	public Response getVote(@PathParam("conId") long conId, @PathParam("userId") String userId) {
		try (ManagersBundle mb = new ManagersBundle()) {
			Consensus con = mb.rm.getConsensus(conId);
			User user = mb.lm.get(userId);
			Boolean vote = mb.rm.getVote(con, user);
			if (vote == null) {
				throw new InvalidKeyException(userId);
			}
			mb.commit();
			return Response.ok(vote).build();
		} catch (InvalidKeyException e) {
			return Response.status(Status.NOT_FOUND).build();
		} catch (RuntimeException | SQLException e) {
			return handleException(e);
		}
	}

	@GET
	@Path("/{conId}/votes")
	@Produces(MediaType.APPLICATION_JSON)
	public Response getVotes(@PathParam("conId") long conId) {
		try (ManagersBundle mb = new ManagersBundle()) {
			Consensus con = mb.rm.getConsensus(conId);
			Collection<Pair<User, Boolean>> votes = mb.rm.getAllVotes(con);
			JSONArray result = new JSONArray();
			for (Pair<User, Boolean> vote : votes) {
				JSONObject object = new JSONObject();
				object.put("vote", vote.second);
				object.put("userId", vote.first.getId());
				result.put(object);
			}
			mb.commit();
			return Response.ok(result).build();
		} catch (InvalidKeyException e) {
			return Response.status(Status.NOT_FOUND).build();
		} catch (RuntimeException | SQLException e) {
			return handleException(e);
		}
	}

	@GET
	@Path("/{conId}/hasReached")
	public Response getResult(@PathParam("conId") long conId) {
		try (ManagersBundle mb = new ManagersBundle()) {
			Consensus con = mb.rm.getConsensus(conId);
			Boolean result = mb.rm.getConsensusStatus(con);
			mb.commit();
			return Response.ok(result).build();
		} catch (InvalidKeyException e) {
			return Response.status(Status.NOT_FOUND).build();
		} catch (RuntimeException | SQLException e) {
			return handleException(e);
		}
	}

	@POST
	@Path("/{conId}/votes")
	public Response vote(@PathParam("conId") long conId, JSONObject object,
			@CookieParam(value = UsersResource.COOKIE_NAME) Long sessionId) {
		try (ManagersBundle mb = new ManagersBundle()) {
			if (sessionId == null) {
				return missingCookie();
			}
			User user = null;
			try {
				String userId = mb.lm.getSession(sessionId).getUser().getId();
				user = mb.lm.get(userId);
			} catch (InvalidKeyException e) {
				return missingCookie();
			}
			Consensus con = mb.rm.getConsensus(conId);
			boolean vote = object.getBoolean("vote");
			Response response = null;
			if (mb.rm.getVote(con, user) == null) {
				response = Response.created(new URI(user.getId())).build();
			} else {
				response = Response.ok().build();
			}
			mb.rm.vote(con, user, vote);
			mb.commit();
			return response;
		} catch (JSONException e) {
			return handleJsonException(e);
		} catch (InvalidKeyException e) {
			return Response.status(Status.NOT_FOUND).build();
		} catch (IllegalArgumentException e) {
			return Response.serverError().status(Status.BAD_REQUEST)
					.entity("You are not registered to this event").build();
		} catch (EventOverException e) {
			return Response.status(Status.BAD_REQUEST).entity(e.getMessage()).build();
		} catch (RuntimeException | URISyntaxException | SQLException e) {
			return handleException(e);
		}
	}
}
